//
// @Author: zhengqi Wu
// @Description:
// @Version: 1.0.0
// @Date: 2021/3/14 3:30 下午
// @Copyright: MIN-Group；国家重大科技基础设施——未来网络北大实验室；深圳市信息论与未来网络重点实验室
//

//
// 表示一个标识的封装 TLV
//
// @Description:
//	1. TLV-TYPE -> 指示不同的标识类型，如：102 为通用的身份标识
//	2. TLV-VALUE -> 指示一个 Identifier
//	3. 具体格式如下：
//		IdentifierWrapper = TLV-TYPE TLV-LENGTH
//                   <Identifier>
//

const encoding = require('../encoding')
const {Identifier} = require('./Identifier')
const {TlvComponentBase} = require('./TlvComponentBase')
var aggregation = require('../common/aggregation')//实现了多继承

class IdentifierWrapper extends aggregation(TlvComponentBase,encoding.SelfEncodingBase){
    constructor() {
        super();
        this.identifier = new Identifier()
        this.tlvType = 0n // vlint
    }

    /**
     * @description 判断是否有效
     * @returns {boolean}
     */
    isValid(){
        return encoding.tlv.isValidIdentifierType(this.tlvType)
    }

    /**
     * @description 获取 identifier 对象
     * @returns {Identifier}
     */
    getIdentifier(){
        return this.identifier
    }

    /**
     * @description 获取 identifier 对象类型
     * @returns {Identifier}
     */
    getIdentifierType(){
        return this.tlvType
    }

    /**
     * @description 将 IdentifierWrapper 表示成Uri 字符串
     * @returns {string}
     */
    toUri(){
        return this.identifier.toUri()
    }

    /**
     * @description 对 IdentifierWrapper 执行线速编码
     * @param enc
     * @returns {number}
     */
    wireEncode(enc){
        let totalLength = 0
        try{
            // 编码TLV-VALUE
            let tmpLen = this.identifier.wireEncode(enc)
            // DONE 错误处理
            totalLength += tmpLen

            // 编码TLV-LENGTH
            tmpLen = enc.prependVarNumber((totalLength))
            // DONE 错误处理
            totalLength += tmpLen

            // 编码 TLV-TYPE
            tmpLen = enc.prependVarNumber(this.tlvType)
            // DONE 错误处理
            totalLength += tmpLen

            return totalLength
        }catch (e){
            throw e
        }

    }

    /**
     * @description     线速解码，从 TLV Block 中解码一个 IdentifierWrapper
     * @param block
     */
    wireDecode(block){
        try{
            if(encoding.tlv.isValidIdentifierType(block.getType())){
                // 解析子 TLV
                block.parseSubElements();
                // 判断是否有且仅有一个子TLV
                if(block.getSubElements().length === 1){
                    this.identifier.buildIdentifierByBlock(block.getSubElements()[0])
                    this.tlvType = block.getType()
                }
            }
        }catch (e){
            throw e
        }
    }
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////
///// 构造函数 Create*
/////////////////////////////////////////////////////////////////////////////////////////////////////////

/**
 * @description 从一个 IdentifierWrapper 编码成的 TLV Block 中解析出一个 IdentifierWrapper
 * @param block
 * @returns {IdentifierWrapper|null}
 */
function createIdentifierWrapperByBlock(block) {
    try{
        block.parseSubElements()
        if(block.getSubElements().length === 1 && block.getSubElements()[0].getType() === encoding.tlv.ComponentType.TlvIdentifier){
            return createCustomIdentifierByBlock(block.getType(), block.getSubElements()[0])
        }else{
            throw new IdentifierWrapperError()
        }
    }catch (e){
        throw e
    }

}

/**
 * @description 根据 tlvType 和 identifier 创建一个 IdentifierWrapper
 * @param tlvType
 * @param identifier
 */
function createIdentifierWrapperByTypeAndIdentifier(tlvType, identifier){
    try{
        let identifierWrapper = new IdentifierWrapper()
        identifierWrapper.tlvType = tlvType
        identifierWrapper.identifier.buildIdentifierByComponents(identifier.getComponents())
        return identifierWrapper // fixed
    }catch (e){
        throw e
    }

}

/**
 * @description 自定义标识类型，根据标识的字符串标识创建一个自定义的标识
 * @param tlvType
 * @param identifierString
 * @returns {IdentifierWrapper|null}
 */
function createCustomIdentifierByString(tlvType, identifierString){
    try{
        if(encoding.tlv.isValidIdentifierType(tlvType)){
            let identifierWrapper = new IdentifierWrapper()
            identifierWrapper.tlvType = tlvType
            identifierWrapper.identifier.buildIdentifierByString(identifierString)
            return identifierWrapper
        }else{
            throw new IdentifierWrapperError()
        }
    }catch (e){
        throw e
    }
}
/**
 * @description 自定义标识类型，根据 components 创建一个自定义的标识
 * @param tlvType
 * @param container
 * @returns {IdentifierWrapper|null}
 */
function createCustomIdentifierByComponents(tlvType, container) {
    try{
        if(encoding.tlv.isValidIdentifierType(tlvType)){
            let identifierWrapper = new IdentifierWrapper()
            identifierWrapper.tlvType = tlvType
            identifierWrapper.identifier.buildIdentifierByComponents(container)
            return identifierWrapper
        }else{
            throw new IdentifierWrapperError()
        }
    }catch (e){
        throw e
    }

}

/**
 * @description 自定义标识类型，根据 block 创建一个自定义的标识
 * @param tlvType
 * @param block
 * @returns {IdentifierWrapper|null}
 */
function createCustomIdentifierByBlock(tlvType, block) {
    try{
        if(encoding.tlv.isValidIdentifierType(tlvType)){
            let identifierWrapper = new IdentifierWrapper()
            identifierWrapper.tlvType = tlvType
            identifierWrapper.identifier.buildIdentifierByBlock(block)
            return identifierWrapper
        }else {
            throw new IdentifierWrapperError()
        }
    }catch (e){
        throw e
    }

}

/**
 * @description 根据标识的字符串表示创建一个通用的身份标识
 * @param identifierString
 * @returns {IdentifierWrapper}
 */
function createCommonIdentifierByString(identifierString) {
    try{
        let identifierWrapper = new IdentifierWrapper()
        identifierWrapper.tlvType = (encoding.tlv.ComponentType.TlvIdentifierCommon)
        // if(identifierString.length > 0 && identifierString[0] !== '/'){
        //     identifierString = '/' + identifierString
        // }
        identifierWrapper.identifier.buildIdentifierByString(identifierString)
        return identifierWrapper
    }catch (e){
        throw e
    }

}

/**
 * @description 根据components构造一个通用的身份标识
 * @param container
 * @returns {IdentifierWrapper}
 */
function createCommonIdentifierByComponents(container) {
    try{
        let identifierWrapper = new IdentifierWrapper()
        identifierWrapper.tlvType = (encoding.tlv.ComponentType.TlvIdentifierCommon)
        identifierWrapper.identifier.buildIdentifierByComponents(container)
        return identifierWrapper
    }catch (e){
        throw e
    }

}

/**
 * @description 根据 TLV Block 构造一个通用的身份标识
 * @param block
 * @returns {IdentifierWrapper}
 */
function createCommonIdentifierByBlock(block) {
    try{
        let identifierWrapper = new IdentifierWrapper()
        identifierWrapper.tlvType = (encoding.tlv.ComponentType.TlvIdentifierCommon)
        identifierWrapper.identifier.buildIdentifierByBlock(block)
        return identifierWrapper
    }catch (e){
        throw e
    }

}

/**
 * @description 根据标识的字符串表示创建一个内容兴趣标识
 * @param identifierString
 * @returns {IdentifierWrapper}
 */
function createContentInterestIdentifierByString(identifierString) {
    try{
        let identifierWrapper = new IdentifierWrapper()
        identifierWrapper.tlvType = (encoding.tlv.ComponentType.TlvIdentifierContentInterest)
        identifierWrapper.identifier.buildIdentifierByString(identifierString)
        return identifierWrapper
    }catch (e){
        throw e
    }

}

/**
 * @description 根据components构造一个内容兴趣标识
 * @param container
 * @returns {IdentifierWrapper}
 */
function createContentInterestIdentifierByComponents(container) {
    try{
        let identifierWrapper = new IdentifierWrapper()
        identifierWrapper.tlvType = (encoding.tlv.ComponentType.TlvIdentifierContentInterest)
        identifierWrapper.identifier.buildIdentifierByComponents(container)
        return identifierWrapper
    }catch (e){
        throw e
    }

}

/**
 * @description 根据 TLV Block 构造一个内容兴趣标识
 * @param block
 * @returns {IdentifierWrapper}
 */
function createContentInterestIdentifierByBlock(block) {
    try{
        let identifierWrapper = new IdentifierWrapper()
        identifierWrapper.tlvType = (encoding.tlv.ComponentType.TlvIdentifierContentInterest)
        identifierWrapper.identifier.buildIdentifierByBlock(block)
        return identifierWrapper
    }catch (e){
        throw e
    }

}

/**
 * @description 根据标识的字符串表示创建一个内容数据标识
 * @param identifierString
 * @returns {IdentifierWrapper}
 */
function createContentDataIdentifierByString(identifierString) {
    try {
        let identifierWrapper = new IdentifierWrapper()
        identifierWrapper.tlvType = (encoding.tlv.ComponentType.TlvIdentifierContentData)
        identifierWrapper.identifier.buildIdentifierByString(identifierString)
        return identifierWrapper
    }catch (e) {
        throw e
    }
}

/**
 * @description 根据components构造一个内容数据标识
 * @param container
 * @returns {IdentifierWrapper}
 */
function createContentDataIdentifierByComponents(container) {
    try{
        let identifierWrapper = new IdentifierWrapper()
        identifierWrapper.tlvType = (encoding.tlv.ComponentType.TlvIdentifierContentData)
        identifierWrapper.identifier.buildIdentifierByComponents(container)
        return identifierWrapper
    }catch (e){
        throw e
    }

}

/**
 * @description 根据 TLV Block 构造一个内容数据标识
 * @returns {IdentifierWrapper}
 */
function createContentDataIdentifierByBlock(block) {
    try{
        let identifierWrapper = new IdentifierWrapper()
        identifierWrapper.tlvType = (encoding.tlv.ComponentType.TlvIdentifierContentData)
        identifierWrapper.identifier.buildIdentifierByBlock(block)
        return identifierWrapper
    }catch (e){
        throw e
    }

}

class IdentifierWrapperError extends Error{
    constructor(m){
        super(m)
        this.name = 'BlockError'
    }

    error(){
        console.log(`{this.name}: {this.message}`)
    }
}

module.exports = {
    createCustomIdentifierByString: createCustomIdentifierByString,
    createCustomIdentifierByComponents: createCustomIdentifierByComponents,
    createCustomIdentifierByBlock: createCustomIdentifierByBlock,
    createCommonIdentifierByString: createCommonIdentifierByString,
    createCommonIdentifierByComponents: createCommonIdentifierByComponents,
    createContentDataIdentifierByString: createContentDataIdentifierByString,
    createContentDataIdentifierByComponents: createContentDataIdentifierByComponents,
    createContentDataIdentifierByBlock: createContentDataIdentifierByBlock,
    createCommonIdentifierByBlock: createCommonIdentifierByBlock,
    createContentInterestIdentifierByComponents: createContentInterestIdentifierByComponents,
    createContentInterestIdentifierByString: createContentInterestIdentifierByString,
    createContentInterestIdentifierByBlock: createContentInterestIdentifierByBlock,
    IdentifierWrapper, IdentifierWrapper,
    createIdentifierWrapperByTypeAndIdentifier: createIdentifierWrapperByTypeAndIdentifier,
    createIdentifierWrapperByBlock: createIdentifierWrapperByBlock
}